﻿

#include "OccWidget.hpp"
#include "../OLApp/Application.hpp"

#include <Aspect_DisplayConnection.hxx>
#include <OpenGl_GraphicDriver.hxx>
#include <AIS_InteractiveContext.hxx>
#include <Prs3d_DatumAspect.hxx>
#include <Resource_Unicode.hxx>
#include <AIS_RubberBand.hxx>
#include <WNT_Window.hxx>
#include <V3d_View.hxx>

#include <AIS_Shape.hxx>
#include <BRepPrimAPI_MakeBox.hxx>

#include <QWheelEvent>
#include <QPainter>

namespace NSWidgets {

    OccWidget::OccWidget(QWidget* p) :
        ViewWidget(p),
        AIS_ViewController()
    {
        /*初始化*/
        setAttribute(Qt::WA_PaintOnScreen);
        //setAttribute(Qt::WA_NoSystemBackground);
        setBackgroundRole(QPalette::NoRole);
        setFocusPolicy(Qt::StrongFocus);
        setMouseTracking(true);
        if (m_context.IsNull()) {
            //此对象提供与X server的连接，在Windows和Mac OS中不起作用
            Handle(Aspect_DisplayConnection) m_display_connection = new Aspect_DisplayConnection();
            //创建OpenGl图形驱动
            if (m_graphic_driver.IsNull()) {
                m_graphic_driver = new OpenGl_GraphicDriver(m_display_connection);
            }
            //获取QWidget的窗口系统标识符
            WId window_handle = (WId)winId();
            // 创建Windows NT 窗口
            Handle(WNT_Window) wind = new WNT_Window((Aspect_Handle)window_handle);
            //创建3D查看器
            m_viewer = new V3d_Viewer(m_graphic_driver);
            //创建视图
            m_view = m_viewer->CreateView();
            m_view->SetWindow(wind);
            //打开窗口
            if (!wind->IsMapped()) {
                wind->Map();
                
            }
            //创建交互式上下文
            m_context = new AIS_InteractiveContext(m_viewer);
            m_context->DefaultDrawer()->SetFaceBoundaryDraw(Standard_True);
            //设置查看器的光照
            m_viewer->SetDefaultLights();
            //打开背景灯光
            m_viewer->SetLightOn();
            //设置视图的背景颜色为黑色
            m_view->SetBackgroundColor(Quantity_NOC_BLACK);
            /*显示直角坐标系，可以配置在窗口显示位置、文字颜色、大小、样式*/
            m_view->TriedronDisplay(Aspect_TOTP_LEFT_LOWER, Quantity_NOC_BLACK, 0.12, V3d_WIREFRAME);
            /*通过提供颜色和填充方法(默认为水平)来定义视图的渐变背景色*/
            m_view->SetBgGradientColors(Quantity_NOC_GRAY, Quantity_NOC_WHITE, Aspect_GFM_VER);
            m_view->MustBeResized();
            /*建模测试*/
            
            TopoDS_Shape box = BRepPrimAPI_MakeBox(1.0,1.0,1.0).Shape();
            Handle(AIS_Shape) aix_box = new AIS_Shape(box);
           Quantity_Color color = Quantity_Color(0.3, 0.5, 0.3, Quantity_TOC_RGB);
            m_context->SetMaterial(aix_box, Graphic3d_NameOfMaterial_Stone, Standard_False);
            m_context->SetColor(aix_box, color, Standard_False);
            m_context->Display(aix_box, 1,1,Standard_True);

            /*建立视角立方体*/
            Handle(AIS_ViewCube) H_AisViewCube = Create_AIS_ViewCube();
            m_context->Display(H_AisViewCube, Standard_True);
            /*显示文字*/
            Handle(AIS_TextLabel) H_Label = Create_AIS_2DLabel("Origin.");
            m_context->Display(H_Label, Standard_True);

            /* 设置交互式上下文的显示模式*/
            m_context->SetDisplayMode(AIS_Shaded, Standard_True);
        }
        //初始化选择框
        m_selection_rect = new AIS_RubberBand();
        m_selection_rect->SetLineType(Aspect_TOL_DASH); // 设置线条类型为实线  
        m_selection_rect->SetLineColor(Quantity_NOC_BLACK); // 设置线条颜色为黑色

        m_viewer->Redraw();
        m_view->FitAll();

    }

    OccWidget::~OccWidget()
    {

    }

    Handle(AIS_TextLabel) OccWidget::Create_AIS_2DLabel(Standard_CString _str) {
        TCollection_ExtendedString tostr;
        Resource_Unicode::ConvertGBToUnicode(_str, tostr);
        Handle(AIS_TextLabel) a_Label = new AIS_TextLabel();
        a_Label->SetPosition(gp_Pnt(0, 0, 0)); // 设置文本位置
        a_Label->SetText(tostr);
        a_Label->SetColor(Quantity_NOC_RED);
        a_Label->SetFont("Microsoft YaHei");//一定要设置合适的字体，不然不能实现功能
        /*显示点*/

        return a_Label;
    }


    Handle(AIS_ViewCube) OccWidget::Create_AIS_ViewCube() {
        //设置视方体
        Handle(AIS_ViewCube) H_AisViewCube = new AIS_ViewCube();
        //下面是自定义每个面的文本
        H_AisViewCube->SetBoxSideLabel(V3d_Xpos, "Right");
        H_AisViewCube->SetBoxSideLabel(V3d_Ypos, "Back");
        H_AisViewCube->SetBoxSideLabel(V3d_Zpos, "Top");
        H_AisViewCube->SetBoxSideLabel(V3d_Xneg, "Left");
        H_AisViewCube->SetBoxSideLabel(V3d_Yneg, "Front");
        H_AisViewCube->SetBoxSideLabel(V3d_Zneg, "Bottom");
        H_AisViewCube->SetSize(45.0, Standard_True);
        H_AisViewCube->SetBoxColor(Quantity_NOC_WHITE); //设置视方体为白色
        H_AisViewCube->SetTransparency(0.8);
        //设置视方体每个面的字体为黑色
        H_AisViewCube->SetTextColor(Quantity_Color(Quantity_NOC_MATRABLUE));
        H_AisViewCube->SetFontHeight(18);

        //设置视方体每个面的边界线
        const Handle(Prs3d_Drawer)& drawer = H_AisViewCube->Attributes();
        drawer->SetupOwnFaceBoundaryAspect();
        drawer->SetFaceBoundaryDraw(true);
        //设置边界线的颜色为Quantity_NOC_GRAY
        drawer->FaceBoundaryAspect()->SetColor(Quantity_NameOfColor::Quantity_NOC_GREENYELLOW);
        drawer->FaceBoundaryAspect()->SetWidth(0.5);
        H_AisViewCube->SetMaterial(Graphic3d_MaterialAspect(Graphic3d_NOM_DEFAULT));

        //设置视方体基准线
        drawer->SetDatumAspect(new Prs3d_DatumAspect());
        const Handle_Prs3d_DatumAspect& datumAspect = H_AisViewCube->Attributes()->DatumAspect();
        //设置轴颜色
        datumAspect->ShadingAspect(Prs3d_DP_XAxis)->SetColor(Quantity_NOC_RED);
        datumAspect->ShadingAspect(Prs3d_DP_YAxis)->SetColor(Quantity_NOC_GREEN);
        datumAspect->ShadingAspect(Prs3d_DP_ZAxis)->SetColor(Quantity_NOC_BLUE);
        //设置X,Y,Z文本颜色
        datumAspect->TextAspect(Prs3d_DP_XAxis)->SetColor(Quantity_NOC_RED);
        datumAspect->TextAspect(Prs3d_DP_YAxis)->SetColor(Quantity_NOC_GREEN);
        datumAspect->TextAspect(Prs3d_DP_ZAxis)->SetColor(Quantity_NOC_BLUE);
        /*设置在右上角*/
        H_AisViewCube->SetTransformPersistence(
            new Graphic3d_TransformPers(
                Graphic3d_TMF_TriedronPers,
                Aspect_TOTP_RIGHT_UPPER,
                Graphic3d_Vec2i(100, 100)));


        return H_AisViewCube;

    }


    void OccWidget::mouseReleaseEvent(QMouseEvent* event) {
        m_mode = Nothings;
        /*如果松开左键-取消矩形框*/
        if (event->button() & Qt::LeftButton && m_context->IsDisplayed(m_selection_rect)) {
            m_context->Remove(m_selection_rect, Standard_True);
            m_view->Update();
        }
        //for (m_context->InitSelected(); m_context->MoreSelected(); m_context->NextSelected()){
        //    //选取的asi显示对象
        //    Handle(AIS_InteractiveObject)  aisObj = m_context->SelectedInteractive();
        //    //选的具体对象边 线 面
        //    TopoDS_Shape aShape = m_context->SelectedShape();
        //    if (aShape.IsNull())
        //        return;
        //    //选取的shape对象类型	
        //    std::string strType = "NULL";
        //    TopAbs_ShapeEnum aShapeType = aShape.ShapeType();
        //    switch (aShapeType){
        //    case TopAbs_COMPOUND:
        //        strType = "TopAbs_COMPOUND";
        //        break;
        //    case TopAbs_COMPSOLID:
        //        strType = "TopAbs_COMPSOLID";
        //        break;
        //    case TopAbs_SOLID:
        //        strType = "TopAbs_SOLID";
        //        break;
        //    case TopAbs_SHELL:
        //        strType = "TopAbs_SHELL";
        //        break;
        //    case TopAbs_FACE:
        //        strType = "TopAbs_FACE";
        //        break;
        //    case TopAbs_WIRE:
        //        strType = "TopAbs_WIRE";
        //        break;
        //    case TopAbs_EDGE:
        //        strType = "TopAbs_EDGE";
        //        break;
        //    case TopAbs_VERTEX:
        //        strType = "TopAbs_VERTEX";
        //        break;
        //    case TopAbs_SHAPE:
        //        strType = "TopAbs_SHAPE";
        //        break;
        //    default:
        //        break;
        //    }

        //    //QMessageBox::information(this, tr("选取"), tr(strType.c_str()));
        //}

    }

    void OccWidget::mousePressEvent(QMouseEvent* event) {
        /*设置选择框的开始点*/
        select_start_x = event->pos().x();
        select_start_y = event->pos().y();
        /*消息处理*/
        if (event->buttons() & Qt::RightButton) {
            m_mode = Panning;
            m_x = event->pos().x();
            m_y = event->pos().y();
        }
        else if (event->buttons() & Qt::MidButton) {
            m_mode = Rotation;
            m_view->StartRotation(event->pos().x(), event->pos().y());
        }
        else if (event->buttons() & Qt::LeftButton) {
            m_mode = Selection;
            select_start_x = event->pos().x();
            select_start_y = event->pos().y();
            /*查看选中的模型*/
            AIS_StatusOfPick sta = m_context->Select(false);
            m_context->UpdateSelected(true);
        }
    }


    void OccWidget::mouseMoveEvent(QMouseEvent* event) {
        Q_UNUSED(event);
        m_context->MoveTo(event->pos().x(), event->pos().y(), m_view, Standard_True);
        switch (m_mode) {
        case OccWidget::Nothings:
            break;
        case OccWidget::Panning:
            m_view->Pan(event->pos().x() - m_x, m_y - event->pos().y());
            m_x = event->pos().x();
            m_y = event->pos().y();
            break;
        case OccWidget::Rotation:
            m_view->Rotation(event->pos().x(), event->pos().y());
            break;
        case OccWidget::Selection:
            m_context->Select(select_start_x, select_start_y, event->pos().x(), event->pos().y(), m_view, Standard_True);
            // TODO:  在此添加命令处理程序代码
            m_view->Window()->Size(view_width, view_height);//获取窗体尺寸
            //设置矩形边界
            m_selection_rect->SetRectangle(select_start_x, view_height - select_start_y, event->pos().x(), view_height - event->pos().y());
            //更新或显示选择框
            if (m_context->IsDisplayed(m_selection_rect))
                m_context->Redisplay(m_selection_rect, Standard_True);
            else
                m_context->Display(m_selection_rect, Standard_True);

            break;
        default:
            break;
        }
    }

    void OccWidget::paintEvent(QPaintEvent*) {
        if (!m_view.IsNull()) {
            if (paint_t == -1) m_view->MustBeResized();
            if (paint_t++ / 4) {
                paint_t = 0;
                m_view->MustBeResized();
            }
        }
    }

    void OccWidget::resizeEvent(QResizeEvent*) {
        if (!m_view.IsNull()) {
            m_view->Redraw();
        }
    }

    QPaintEngine* OccWidget::paintEngine() const {
        
        
        return 0;
    }

    void OccWidget::wheelEvent(QWheelEvent* event) {
        m_view->StartZoomAtPoint(event->position().x(), event->position().y());
        m_view->ZoomAtPoint(0, 0, event->angleDelta().y() * 0.06, 0);
    }

    void OccWidget::setViewWire() {
        m_context->SetDisplayMode(AIS_WireFrame, Standard_True);
    }

    void OccWidget::setViewSolid() {
        m_context->SetDisplayMode(AIS_Shaded, Standard_True);
    }

    void OccWidget::setViewUp() {
        m_view->SetProj(V3d_Zpos, Standard_True);
        m_view->FitAll();
        m_view->ZFitAll();
    }

    void OccWidget::setViewBottom() {
        m_view->SetProj(V3d_Zneg, Standard_True);
        m_view->FitAll();
        m_view->ZFitAll();
    }

    void OccWidget::setViewLeft() {
        m_view->SetProj(V3d_Xneg, Standard_True);
        m_view->FitAll();
        m_view->ZFitAll();
    }

    void OccWidget::setViewRight() {
        m_view->SetProj(V3d_Xpos, Standard_True);
        m_view->FitAll();
        m_view->ZFitAll();
    }

    void OccWidget::setViewFront() {
        m_view->SetProj(V3d_Yneg, Standard_True);
        m_view->FitAll();
        m_view->ZFitAll();
    }

    void OccWidget::setViewBack() {
        m_view->SetProj(V3d_Ypos, Standard_True);
        m_view->FitAll();
        m_view->ZFitAll();
    }

    void OccWidget::setViewSide() {
        m_view->SetProj(V3d_XposYposZpos, Standard_True);
        m_view->FitAll();
        m_view->ZFitAll();
    }

    Handle(AIS_InteractiveContext) OccWidget::get_AIS_Context() {
        return m_context;
    }

    Handle(V3d_View) OccWidget::get_AIS_View() {
        return m_view;
    }

}

